
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Diagnostics;
using System.Threading;
using System.Runtime.CompilerServices;

namespace System.Threading
{

	[HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
	[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
	public class ReaderWriterLockSlim : IDisposable
	{

		#region private fidlds

		private const Int32 hashTableSize = 0xff;
		private const Int32 LockSleep0Count = 5;
		private const Int32 LockSpinCount = 10;
		private const Int32 LockSpinCycles = 20;
		private const UInt32 MAX_READER = 0xffffffe;
		private const Int32 MaxSpinCount = 20;
		private const UInt32 READER_MASK = 0xfffffff;
		private const UInt32 WAITING_UPGRADER = 0x20000000;
		private const UInt32 WAITING_WRITERS = 0x40000000;
		private const UInt32 WRITER_HELD = 0x80000000;
		private readonly Boolean fIsReentrant;
		private Boolean fDisposed;
		private Boolean fNoWaiters;
		private Boolean fUpgradeThreadHoldingRead;
		private Int32 myLock;
		private UInt32 numReadWaiters;
		private UInt32 numUpgradeWaiters;
		private UInt32 numWriteUpgradeWaiters;
		private UInt32 numWriteWaiters;
		private UInt32 owners;
		private EventWaitHandle readEvent;
		private ReaderWriterCount[] rwc;
		private EventWaitHandle upgradeEvent;
		private Int32 upgradeLockOwnerId;
		private EventWaitHandle waitUpgradeEvent;
		private EventWaitHandle writeEvent;
		private Int32 writeLockOwnerId;

		#endregion

		#region public contructs

		public ReaderWriterLockSlim()
			: this(LockRecursionPolicy.NoRecursion)
		{
		}

		public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy)
		{
			if (recursionPolicy == LockRecursionPolicy.SupportsRecursion)
			{
				fIsReentrant = true;
			}
			InitializeThreadCounts();
		}

		#endregion

		#region public properties

		public Int32 CurrentReadCount
		{
			get
			{
				Int32 numReaders = (Int32)GetNumReaders();
				if (upgradeLockOwnerId != -1)
				{
					return (numReaders - 1);
				}
				return numReaders;
			}
		}

		public Boolean IsReadLockHeld
		{
			get { return (RecursiveReadCount > 0); }
		}

		public Boolean IsUpgradeableReadLockHeld
		{
			get { return (RecursiveUpgradeCount > 0); }
		}

		public Boolean IsWriteLockHeld
		{
			get { return (RecursiveWriteCount > 0); }
		}

		public LockRecursionPolicy RecursionPolicy
		{
			get
			{
				if (fIsReentrant)
				{
					return LockRecursionPolicy.SupportsRecursion;
				}
				return LockRecursionPolicy.NoRecursion;
			}
		}

		public Int32 RecursiveReadCount
		{
			get
			{
				Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
				Int32 readercount = 0;
				EnterMyLock();
				ReaderWriterCount threadRWCount = GetThreadRWCount(managedThreadId, true);
				if (threadRWCount != null)
				{
					readercount = threadRWCount.readercount;
				}
				ExitMyLock();
				return readercount;
			}
		}

		public Int32 RecursiveUpgradeCount
		{
			get
			{
				Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
				if (fIsReentrant)
				{
					Int32 upgradecount = 0;
					EnterMyLock();
					ReaderWriterCount threadRWCount = GetThreadRWCount(managedThreadId, true);
					if (threadRWCount != null)
					{
						upgradecount = threadRWCount.rc.upgradecount;
					}
					ExitMyLock();
					return upgradecount;
				}
				if (managedThreadId == upgradeLockOwnerId)
				{
					return 1;
				}
				return 0;
			}
		}

		public Int32 RecursiveWriteCount
		{
			get
			{
				Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
				Int32 writercount = 0;
				if (fIsReentrant)
				{
					EnterMyLock();
					ReaderWriterCount threadRWCount = GetThreadRWCount(managedThreadId, true);
					if (threadRWCount != null)
					{
						writercount = threadRWCount.rc.writercount;
					}
					ExitMyLock();
					return writercount;
				}
				if (managedThreadId == writeLockOwnerId)
				{
					return 1;
				}
				return 0;
			}
		}

		public Int32 WaitingReadCount
		{
			get { return (Int32)numReadWaiters; }
		}

		public Int32 WaitingUpgradeCount
		{
			get { return (Int32)numUpgradeWaiters; }
		}

		public Int32 WaitingWriteCount
		{
			get { return (Int32)numWriteWaiters; }
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			Dispose(true);
		}

		private void Dispose(Boolean disposing)
		{
			if (disposing)
			{
				if (fDisposed)
				{
					throw new ObjectDisposedException(null);
				}
				if (((WaitingReadCount > 0) || (WaitingUpgradeCount > 0)) || (WaitingWriteCount > 0))
				{
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_IncorrectDispose"));
				}
				if ((IsReadLockHeld || IsUpgradeableReadLockHeld) || IsWriteLockHeld)
				{
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_IncorrectDispose"));
				}
				if (writeEvent != null)
				{
					writeEvent.Close();
					writeEvent = null;
				}
				if (readEvent != null)
				{
					readEvent.Close();
					readEvent = null;
				}
				if (upgradeEvent != null)
				{
					upgradeEvent.Close();
					upgradeEvent = null;
				}
				if (waitUpgradeEvent != null)
				{
					waitUpgradeEvent.Close();
					waitUpgradeEvent = null;
				}
				fDisposed = true;
			}
		}

		#endregion

		#region private methods

		private String GetStringFromResource(String key)
		{
			return key;
		}

		private void ClearUpgraderWaiting()
		{
			owners &= 0xdfffffff;
		}

		private void ClearWriterAcquired()
		{
			owners &= 0x7fffffff;
		}

		private void ClearWritersWaiting()
		{
			owners &= 0xbfffffff;
		}

		private void EnterMyLock()
		{
			if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0)
			{
				EnterMyLockSpin();
			}
		}

		private void EnterMyLockSpin()
		{
			Int32 processorCount = Environment.ProcessorCount;
			Int32 num2 = 0;

			while (true)
			{
				if ((num2 < 10) && (processorCount > 1))
				{
					Thread.SpinWait(20 * (num2 + 1));
				}
				else if (num2 < 15)
				{
					Thread.Sleep(0);
				}
				else
				{
					Thread.Sleep(1);
				}
				if ((myLock == 0) && (Interlocked.CompareExchange(ref myLock, 1, 0) == 0))
				{
					return;
				}
				num2++;
			}
		}

		private void ExitAndWakeUpAppropriateWaiters()
		{
			if (fNoWaiters)
			{
				ExitMyLock();
			}
			else
			{
				ExitAndWakeUpAppropriateWaitersPreferringWriters();
			}
		}

		private void ExitAndWakeUpAppropriateWaitersPreferringWriters()
		{
			Boolean flag = false;
			Boolean flag2 = false;
			UInt32 numReaders = GetNumReaders();
			if ((fIsReentrant && (numWriteUpgradeWaiters > 0)) && (fUpgradeThreadHoldingRead && (numReaders == 2)))
			{
				ExitMyLock();
				waitUpgradeEvent.Set();
			}
			else if ((numReaders == 1) && (numWriteUpgradeWaiters > 0))
			{
				ExitMyLock();
				waitUpgradeEvent.Set();
			}
			else if ((numReaders == 0) && (numWriteWaiters > 0))
			{
				ExitMyLock();
				writeEvent.Set();
			}
			else if (numReaders >= 0)
			{
				if ((numReadWaiters == 0) && (numUpgradeWaiters == 0))
				{
					ExitMyLock();
				}
				else
				{
					if (numReadWaiters != 0)
					{
						flag2 = true;
					}
					if ((numUpgradeWaiters != 0) && (upgradeLockOwnerId == -1))
					{
						flag = true;
					}
					ExitMyLock();
					if (flag2)
					{
						readEvent.Set();
					}
					if (flag)
					{
						upgradeEvent.Set();
					}
				}
			}
			else
			{
				ExitMyLock();
			}
		}

		private UInt32 GetNumReaders()
		{
			return (owners & 0xfffffff);
		}

		private ReaderWriterCount GetThreadRWCount(Int32 id, Boolean DontAllocate)
		{
			Int32 index = id & 0xff;
			ReaderWriterCount count = null;
			if (rwc[index].threadid == id)
			{
				return rwc[index];
			}
			if (IsRWEntryEmpty(rwc[index]) && !DontAllocate)
			{
				if (rwc[index].next == null)
				{
					rwc[index].threadid = id;
					return rwc[index];
				}
				count = rwc[index];
			}
			ReaderWriterCount next = rwc[index].next;

			while (next != null)
			{
				if (next.threadid == id)
				{
					return next;
				}
				if ((count == null) && IsRWEntryEmpty(next))
				{
					count = next;
				}
				next = next.next;
			}
			if (DontAllocate)
			{
				return null;
			}
			if (count == null)
			{
				next = new ReaderWriterCount(fIsReentrant);
				next.threadid = id;
				next.next = rwc[index].next;
				rwc[index].next = next;
				return next;
			}
			count.threadid = id;
			return count;
		}

		private void InitializeThreadCounts()
		{
			rwc = new ReaderWriterCount[0x100];

			for (Int32 i = 0; i < rwc.Length; i++)
			{
				rwc[i] = new ReaderWriterCount(fIsReentrant);
			}
			upgradeLockOwnerId = -1;
			writeLockOwnerId = -1;
		}

		private static Boolean IsRWEntryEmpty(ReaderWriterCount rwc)
		{
			return ((rwc.threadid == -1) ||
							(((rwc.readercount == 0) && (rwc.rc == null)) ||
							 (((rwc.readercount == 0) && (rwc.rc.writercount == 0)) && (rwc.rc.upgradecount == 0))));
		}

		private static Boolean IsRwHashEntryChanged(ReaderWriterCount lrwc, Int32 id)
		{
			return (lrwc.threadid != id);
		}

		private Boolean IsWriterAcquired()
		{
			return ((owners & 0xbfffffff) == 0);
		}

		private void LazyCreateEvent(ref EventWaitHandle waitEvent, Boolean makeAutoResetEvent)
		{
			EventWaitHandle handle;
			ExitMyLock();
			if (makeAutoResetEvent)
			{
				handle = new AutoResetEvent(false);
			}
			else
			{
				handle = new ManualResetEvent(false);
			}
			EnterMyLock();
			if (waitEvent == null)
			{
				waitEvent = handle;
			}
			else
			{
				handle.Close();
			}
		}

		private void SetUpgraderWaiting()
		{
			owners |= 0x20000000;
		}

		private void SetWriterAcquired()
		{
			owners |= 0x80000000;
		}

		private void SetWritersWaiting()
		{
			owners |= 0x40000000;
		}

		private static void SpinWait(Int32 SpinCount)
		{
			if ((SpinCount < 5) && (Environment.ProcessorCount > 1))
			{
				Thread.SpinWait(20 * SpinCount);
			}
			else if (SpinCount < 0x11)
			{
				Thread.Sleep(0);
			}
			else
			{
				Thread.Sleep(1);
			}
		}

		private void ExitMyLock()
		{
			myLock = 0;
		}

		private Boolean WaitOnEvent(EventWaitHandle waitEvent, ref UInt32 numWaiters, Int32 millisecondsTimeout)
		{
			waitEvent.Reset();
			numWaiters++;
			fNoWaiters = false;
			if (numWriteWaiters == 1)
			{
				SetWritersWaiting();
			}
			if (numWriteUpgradeWaiters == 1)
			{
				SetUpgraderWaiting();
			}
			Boolean flag = false;
			ExitMyLock();

			try
			{
				flag = waitEvent.WaitOne(millisecondsTimeout, false);
			}
			finally
			{
				EnterMyLock();
				numWaiters--;
				if (((numWriteWaiters == 0) && (numWriteUpgradeWaiters == 0)) &&
						((numUpgradeWaiters == 0) && (numReadWaiters == 0)))
				{
					fNoWaiters = true;
				}
				if (numWriteWaiters == 0)
				{
					ClearWritersWaiting();
				}
				if (numWriteUpgradeWaiters == 0)
				{
					ClearUpgraderWaiting();
				}
				if (!flag)
				{
					ExitMyLock();
				}
			}
			return flag;
		}

		#endregion

		#region public methods

		#region Enter and Exit ReadLock

		public void EnterReadLock()
		{

			TryEnterReadLock(-1);
		}

		public void ExitReadLock()
		{
			Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
			ReaderWriterCount threadRWCount = null;
			EnterMyLock();
			threadRWCount = GetThreadRWCount(managedThreadId, true);
			if (!fIsReentrant)
			{
				if (threadRWCount == null)
				{
					ExitMyLock();
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedRead"));
				}
			}
			else
			{
				if ((threadRWCount == null) || (threadRWCount.readercount < 1))
				{
					ExitMyLock();
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedRead"));
				}
				if (threadRWCount.readercount > 1)
				{
					threadRWCount.readercount--;
					ExitMyLock();
					return;
				}
				if (managedThreadId == upgradeLockOwnerId)
				{
					fUpgradeThreadHoldingRead = false;
				}
			}
			owners--;
			threadRWCount.readercount--;
			ExitAndWakeUpAppropriateWaiters();
		}

		#endregion

		#region Enter and Exit WriteLock

		public void EnterWriteLock()
		{

			TryEnterWriteLock(-1);
		}

		public void ExitWriteLock()
		{
			Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
			if (!fIsReentrant)
			{
				if (managedThreadId != writeLockOwnerId)
				{
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedWrite"));
				}
				EnterMyLock();
			}
			else
			{
				EnterMyLock();
				ReaderWriterCount threadRWCount = GetThreadRWCount(managedThreadId, false);
				if (threadRWCount == null)
				{
					ExitMyLock();
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedWrite"));
				}
				RecursiveCounts rc = threadRWCount.rc;
				if (rc.writercount < 1)
				{
					ExitMyLock();
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedWrite"));
				}
				rc.writercount--;
				if (rc.writercount > 0)
				{
					ExitMyLock();
					return;
				}
			}
			ClearWriterAcquired();
			writeLockOwnerId = -1;
			ExitAndWakeUpAppropriateWaiters();
		}

		#endregion

		#region Enter and Exit UpgradeableReadLock

		public void EnterUpgradeableReadLock()
		{

			TryEnterUpgradeableReadLock(-1);
		}

		public void ExitUpgradeableReadLock()
		{
			Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
			if (!fIsReentrant)
			{
				if (managedThreadId != upgradeLockOwnerId)
				{
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedUpgrade"));
				}
				EnterMyLock();
			}
			else
			{
				EnterMyLock();
				ReaderWriterCount threadRWCount = GetThreadRWCount(managedThreadId, true);
				if (threadRWCount == null)
				{
					ExitMyLock();
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedUpgrade"));
				}
				RecursiveCounts rc = threadRWCount.rc;
				if (rc.upgradecount < 1)
				{
					ExitMyLock();
					throw new SynchronizationLockException(
							GetStringFromResource("SynchronizationLockException_MisMatchedUpgrade"));
				}
				rc.upgradecount--;
				if (rc.upgradecount > 0)
				{
					ExitMyLock();
					return;
				}
				fUpgradeThreadHoldingRead = false;
			}
			owners--;
			upgradeLockOwnerId = -1;
			ExitAndWakeUpAppropriateWaiters();
		}

		#endregion

		#region TryEnterReadLock

		public Boolean TryEnterReadLock(Int32 millisecondsTimeout)
		{
			if (millisecondsTimeout < -1)
			{
				throw new ArgumentOutOfRangeException("millisecondsTimeout");
			}
			if (fDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			ReaderWriterCount lrwc = null;
			Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
			if (!fIsReentrant)
			{
				if (managedThreadId == writeLockOwnerId)
				{
					throw new LockRecursionException(GetStringFromResource("LockRecursionException_ReadAfterWriteNotAllowed"));
				}
				EnterMyLock();
				lrwc = GetThreadRWCount(managedThreadId, false);
				if (lrwc.readercount > 0)
				{
					ExitMyLock();
					throw new LockRecursionException(GetStringFromResource("LockRecursionException_RecursiveReadNotAllowed"));
				}
				if (managedThreadId == upgradeLockOwnerId)
				{
					lrwc.readercount++;
					owners++;
					ExitMyLock();
					return true;
				}
			}
			else
			{
				EnterMyLock();
				lrwc = GetThreadRWCount(managedThreadId, false);
				if (lrwc.readercount > 0)
				{
					lrwc.readercount++;
					ExitMyLock();
					return true;
				}
				if (managedThreadId == upgradeLockOwnerId)
				{
					lrwc.readercount++;
					owners++;
					ExitMyLock();
					fUpgradeThreadHoldingRead = true;
					return true;
				}
				if (managedThreadId == writeLockOwnerId)
				{
					lrwc.readercount++;
					owners++;
					ExitMyLock();
					return true;
				}
			}
			Boolean flag = true;
			Int32 spinCount = 0;
		Label_013D:
			if (owners < 0xffffffe)
			{
				owners++;
				lrwc.readercount++;
			}
			else
			{
				if (spinCount < 20)
				{
					ExitMyLock();
					if (millisecondsTimeout == 0)
					{
						return false;
					}
					spinCount++;
					SpinWait(spinCount);
					EnterMyLock();
					if (IsRwHashEntryChanged(lrwc, managedThreadId))
					{
						lrwc = GetThreadRWCount(managedThreadId, false);
					}
				}
				else if (readEvent == null)
				{
					LazyCreateEvent(ref readEvent, false);
					if (IsRwHashEntryChanged(lrwc, managedThreadId))
					{
						lrwc = GetThreadRWCount(managedThreadId, false);
					}
				}
				else
				{
					flag = WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout);
					if (!flag)
					{
						return false;
					}
					if (IsRwHashEntryChanged(lrwc, managedThreadId))
					{
						lrwc = GetThreadRWCount(managedThreadId, false);
					}
				}
				goto Label_013D;
			}
			ExitMyLock();
			return flag;
		}

		public Boolean TryEnterReadLock(TimeSpan timeout)
		{
			Int64 totalMilliseconds = (Int64)timeout.TotalMilliseconds;
			if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
			{
				throw new ArgumentOutOfRangeException("timeout");
			}
			Int32 millisecondsTimeout = (Int32)timeout.TotalMilliseconds;
			return TryEnterReadLock(millisecondsTimeout);
		}

		#endregion

		#region TryEnterWriteLock

		public Boolean TryEnterWriteLock(Int32 millisecondsTimeout)
		{
			ReaderWriterCount threadRWCount;
			if (millisecondsTimeout < -1)
			{
				throw new ArgumentOutOfRangeException("millisecondsTimeout");
			}
			if (fDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
			Boolean flag = false;
			if (!fIsReentrant)
			{
				if (managedThreadId == writeLockOwnerId)
				{
					throw new LockRecursionException(GetStringFromResource("LockRecursionException_RecursiveWriteNotAllowed"));
				}
				if (managedThreadId == upgradeLockOwnerId)
				{
					flag = true;
				}
				EnterMyLock();
				threadRWCount = GetThreadRWCount(managedThreadId, true);
				if ((threadRWCount != null) && (threadRWCount.readercount > 0))
				{
					ExitMyLock();
					throw new LockRecursionException(GetStringFromResource("LockRecursionException_WriteAfterReadNotAllowed"));
				}
			}
			else
			{
				EnterMyLock();
				threadRWCount = GetThreadRWCount(managedThreadId, false);
				if (managedThreadId == writeLockOwnerId)
				{
					threadRWCount.rc.writercount++;
					ExitMyLock();
					return true;
				}
				if (managedThreadId == upgradeLockOwnerId)
				{
					flag = true;
				}
				else if (threadRWCount.readercount > 0)
				{
					ExitMyLock();
					throw new LockRecursionException(GetStringFromResource("LockRecursionException_WriteAfterReadNotAllowed"));
				}
			}
			Int32 spinCount = 0;
		Label_00EC:
			if (IsWriterAcquired())
			{
				SetWriterAcquired();
			}
			else
			{
				if (flag)
				{
					UInt32 numReaders = GetNumReaders();
					if (numReaders == 1)
					{
						SetWriterAcquired();
						goto Label_01DD;
					}
					if ((numReaders == 2) && (threadRWCount != null))
					{
						if (IsRwHashEntryChanged(threadRWCount, managedThreadId))
						{
							threadRWCount = GetThreadRWCount(managedThreadId, false);
						}
						if (threadRWCount.readercount > 0)
						{
							SetWriterAcquired();
							goto Label_01DD;
						}
					}
				}
				if (spinCount < 20)
				{
					ExitMyLock();
					if (millisecondsTimeout == 0)
					{
						return false;
					}
					spinCount++;
					SpinWait(spinCount);
					EnterMyLock();
					goto Label_00EC;
				}
				if (flag)
				{
					if (waitUpgradeEvent != null)
					{
						if (!WaitOnEvent(waitUpgradeEvent, ref numWriteUpgradeWaiters, millisecondsTimeout))
						{
							return false;
						}
					}
					else
					{
						LazyCreateEvent(ref waitUpgradeEvent, true);
					}
					goto Label_00EC;
				}
				if (writeEvent == null)
				{
					LazyCreateEvent(ref writeEvent, true);
					goto Label_00EC;
				}
				if (WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout))
				{
					goto Label_00EC;
				}
				return false;
			}
		Label_01DD:
			if (fIsReentrant)
			{
				if (IsRwHashEntryChanged(threadRWCount, managedThreadId))
				{
					threadRWCount = GetThreadRWCount(managedThreadId, false);
				}
				threadRWCount.rc.writercount++;
			}
			ExitMyLock();
			writeLockOwnerId = managedThreadId;
			return true;
		}

		public Boolean TryEnterWriteLock(TimeSpan timeout)
		{
			Int64 totalMilliseconds = (Int64)timeout.TotalMilliseconds;
			if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
			{
				throw new ArgumentOutOfRangeException("timeout");
			}
			Int32 millisecondsTimeout = (Int32)timeout.TotalMilliseconds;
			return TryEnterWriteLock(millisecondsTimeout);
		}

		#endregion

		#region TryEnterUpgradeableReadLock

		public Boolean TryEnterUpgradeableReadLock(Int32 millisecondsTimeout)
		{
			ReaderWriterCount threadRWCount;
			if (millisecondsTimeout < -1)
			{
				throw new ArgumentOutOfRangeException("millisecondsTimeout");
			}
			if (fDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			Int32 managedThreadId = Thread.CurrentThread.ManagedThreadId;
			if (!fIsReentrant)
			{
				if (managedThreadId == upgradeLockOwnerId)
				{
					throw new LockRecursionException(
							GetStringFromResource("LockRecursionException_RecursiveUpgradeNotAllowed"));
				}
				if (managedThreadId == writeLockOwnerId)
				{
					throw new LockRecursionException(
							GetStringFromResource("LockRecursionException_UpgradeAfterWriteNotAllowed"));
				}
				EnterMyLock();
				threadRWCount = GetThreadRWCount(managedThreadId, true);
				if ((threadRWCount != null) && (threadRWCount.readercount > 0))
				{
					ExitMyLock();
					throw new LockRecursionException(
							GetStringFromResource("LockRecursionException_UpgradeAfterReadNotAllowed"));
				}
			}
			else
			{
				EnterMyLock();
				threadRWCount = GetThreadRWCount(managedThreadId, false);
				if (managedThreadId == upgradeLockOwnerId)
				{
					threadRWCount.rc.upgradecount++;
					ExitMyLock();
					return true;
				}
				if (managedThreadId == writeLockOwnerId)
				{
					owners++;
					upgradeLockOwnerId = managedThreadId;
					threadRWCount.rc.upgradecount++;
					if (threadRWCount.readercount > 0)
					{
						fUpgradeThreadHoldingRead = true;
					}
					ExitMyLock();
					return true;
				}
				if (threadRWCount.readercount > 0)
				{
					ExitMyLock();
					throw new LockRecursionException(
							GetStringFromResource("LockRecursionException_UpgradeAfterReadNotAllowed"));
				}
			}
			Int32 spinCount = 0;
		Label_0139:
			if ((upgradeLockOwnerId == -1) && (owners < 0xffffffe))
			{
				owners++;
				upgradeLockOwnerId = managedThreadId;
			}
			else
			{
				if (spinCount < 20)
				{
					ExitMyLock();
					if (millisecondsTimeout == 0)
					{
						return false;
					}
					spinCount++;
					SpinWait(spinCount);
					EnterMyLock();
					goto Label_0139;
				}
				if (upgradeEvent == null)
				{
					LazyCreateEvent(ref upgradeEvent, true);
					goto Label_0139;
				}
				if (WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, millisecondsTimeout))
				{
					goto Label_0139;
				}
				return false;
			}
			if (fIsReentrant)
			{
				if (IsRwHashEntryChanged(threadRWCount, managedThreadId))
				{
					threadRWCount = GetThreadRWCount(managedThreadId, false);
				}
				threadRWCount.rc.upgradecount++;
			}
			ExitMyLock();
			return true;
		}

		public Boolean TryEnterUpgradeableReadLock(TimeSpan timeout)
		{
			Int64 totalMilliseconds = (Int64)timeout.TotalMilliseconds;
			if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
			{
				throw new ArgumentOutOfRangeException("timeout");
			}
			Int32 millisecondsTimeout = (Int32)timeout.TotalMilliseconds;
			return TryEnterUpgradeableReadLock(millisecondsTimeout);
		}

		#endregion

		#endregion

	}
}
